<!DOCTYPE html>
<html lang="en">
	<head>
		<title>粒子效果-GPU运算</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {background-color: #000;margin: 0px;overflow: hidden;}
		</style>
	</head>
	<body>
		<div id="container"></div>
		<script src="//tgideas.qq.com/2017/three/lib/three.r78.min.js"></script>
		<script src="//tgideas.qq.com/2017/three/lib/stats.min.js"></script>
		<script src="//tgideas.qq.com/2017/three/lib/tween.min.js"></script>
		<script type="x-shader/x-vertex" id="vertexshader">

			attribute float size;
			attribute vec3 position2;
			// attribute vec3 color;
			uniform float val;
			// varying vec3 vColor;
			varying vec3 vPos;

			void main() {

				// vColor = color;
				vPos.x = position.x * val + position2.x * (1.-val);
				vPos.y = position.y* val + position2.y * (1.-val);
				vPos.z = position.z* val + position2.z * (1.-val);

				vec4 mvPosition = modelViewMatrix * vec4( vPos, 1.0 );

				gl_PointSize = size * ( 300.0 / -mvPosition.z );

				gl_Position = projectionMatrix * mvPosition;

			}

		</script>

		<script type="x-shader/x-fragment" id="fragmentshader">
			uniform vec3 color;
			uniform sampler2D texture;

			// varying vec3 vColor;
			varying vec3 vPos;

			void main() {

				vec3 vColor = vec3(1.0, 0., 0.);
				vColor.r = vPos.z/50.;
				vColor.g = vPos.y/50.;
				vColor.b = vPos.x/50.;

				gl_FragColor = vec4( color * vColor, 1.0 );

				gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );

			}


		</script>
		<script type="text/javascript">
			var app = {
				init: function(){
					var self = this;
					var renderer, scene, camera, stats, tween;
					var WIDTH = window.innerWidth;
					var HEIGHT = window.innerHeight;
					var container = document.getElementById('container');
					camera = new THREE.PerspectiveCamera(40, WIDTH/HEIGHT, 1, 10000 );
					camera.position.z = 150;
					scene = new THREE.Scene();


					// add light
					var light = new THREE.DirectionalLight( 0xffffff );
					light.position.set( 0, 200, 0 );
					scene.add( light );

					self.addObjs();


					renderer = new THREE.WebGLRenderer();
					renderer.setPixelRatio(window.devicePixelRatio);
					renderer.setSize(WIDTH, HEIGHT);
					
					container.appendChild(renderer.domElement);

					stats = new Stats();
					container.appendChild(stats.dom);

					window.addEventListener( 'resize', function(e){
						self.resize();
					}, false);



					self.scene = scene;
					self.camera = camera;
					self.renderer = renderer;

					// android 微信 崩溃
					// window.requestAnimationFrame(function(time){
					// 	TWEEN.update();
					// 	stats.update();
					// 	self.update(time);
					// 	window.requestAnimationFrame(arguments.callee)
					// });		

					(function(){
						TWEEN.update();
						stats.update();
						self.update();
						window.requestAnimationFrame(arguments.callee)
					})();
				},
				addObjs: function(){
					var self = this;
					var loader = new THREE.JSONLoader();
					var obj1, obj2, loaded;
					loader.load('cpmovie4.json', function(obj) {
						obj.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI/2));
						obj.applyMatrix(new THREE.Matrix4().makeScale(20, 20, 20));
						obj.applyMatrix(new THREE.Matrix4().makeTranslation(80, 20, 0));
						obj1 = obj;
						if(obj1 && obj2 && !loaded) {
							loaded = true;
							self.addPartice(obj1, obj2);
						}
					});	
					loader.load('teapot.js', function(obj) {
						obj2 = obj;
						if(obj1 && obj2 && !loaded) {
							loaded = true;
							self.addPartice(obj1, obj2);
						}
					});	
				},
				addPartice: function(obj1, obj2){
					var moreObj, lessObj;
					if(obj1.vertices.length > obj2.vertices.length) {
						moreObj = obj1;
						lessObj = obj2;
					} else {
						moreObj = obj2;
						lessObj = obj1;
					}
					moreObj = new THREE.BufferGeometry().fromGeometry(moreObj);
					lessObj = new THREE.BufferGeometry().fromGeometry(lessObj);
					var morePos = moreObj.attributes.position.array;
					var lessPos = lessObj.attributes.position.array;
					var moreLen = morePos.length;
					var lessLen = lessPos.length;
					var position2 = new Float32Array(moreLen);
					position2.set(lessPos);
					for(var i = lessLen, j = 0; i < moreLen; i++, j++) {
						j %= lessLen;
						position2[i] = lessPos[j];
						position2[i+1] = lessPos[j+1];
						position2[i+2] = lessPos[j+2];
					}

					var sizes = new Float32Array(moreLen);
					for (var i = 0; i < moreLen; i++) {
						sizes[i] = 4;
					}
					moreObj.addAttribute('size', new THREE.BufferAttribute(sizes, 1));
					moreObj.addAttribute('position2', new THREE.BufferAttribute(position2, 3));
					var uniforms = {
						color:{value: new THREE.Color(0xffffff)},
						texture:{value: new THREE.TextureLoader().load( "//game.gtimg.cn/images/tgideas/2017/three/shader/dot.png")},
						val: {value: 1.0}
					};
					var shaderMaterial = new THREE.ShaderMaterial({
						uniforms:       uniforms,
						vertexShader:   document.getElementById('vertexshader').textContent,
						fragmentShader: document.getElementById('fragmentshader').textContent,
						blending:       THREE.AdditiveBlending,
						depthTest:      false,
						transparent:    true
					});
					particleSystem = new THREE.Points(moreObj, shaderMaterial);
					particleSystem.position.y = -15;


					var pos = {val: 1};
					tween = new TWEEN.Tween(pos).to({val: 0}, 2000).easing(TWEEN.Easing.Quadratic.InOut).delay(1000).onUpdate(callback);
					tweenBack = new TWEEN.Tween(pos).to({val: 1}, 2000).easing(TWEEN.Easing.Quadratic.InOut).delay(1000).onUpdate(callback);
					tween.chain(tweenBack);
					tweenBack.chain(tween);
					tween.start();

					function callback(){
						particleSystem.material.uniforms.val.value = this.val;
					}

					this.scene.add(particleSystem);
					this.particleSystem = particleSystem;		
				},
				resize: function(){
					this.camera.aspect = window.innerWidth/window.innerHeight;
					this.camera.updateProjectionMatrix();

					this.renderer.setSize(window.innerWidth, window.innerHeight);
				},
				update: function(time){
					var time = Date.now() * 0.005;
					if(this.particleSystem) {
						var bufferObj = this.particleSystem.geometry;
						this.particleSystem.rotation.y = 0.01 * time;

						var sizes = bufferObj.attributes.size.array;
						var len = sizes.length;

						for (var i = 0; i < len; i++) {

							sizes[i] = 2 * (1.0 + Math.sin(0.02 * i + time));

						}


						bufferObj.attributes.size.needsUpdate = true;
					}
					
					this.renderer.render(this.scene, this.camera);
				}
			}
			app.init();

		</script>




	</body>
</html>
